package com.controller;

import java.util.Arrays;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.config.Constant;
import com.config.URLConstant;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiCallBackDeleteCallBackRequest;
import com.dingtalk.api.request.OapiCallBackRegisterCallBackRequest;
import com.dingtalk.api.response.OapiCallBackRegisterCallBackResponse;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
import com.dingtalk.oapi.lib.aes.Utils;
import com.enums.ProcessStatus;
import com.model.ProcessInstanceVO;
import com.service.ProcessInstanceService;
import com.util.AuthHelper;
import com.util.MessageUtil;

/**
 * E应用回调信息处理
 */
@RestController
public class CallbackController {

    private static final Logger bizLogger = LoggerFactory.getLogger("BIZ_CALLBACKCONTROLLER");

    @Autowired
    private ProcessInstanceService processInstanceService;
    private static final Logger mainLogger = LoggerFactory.getLogger(CallbackController.class);

    /**
     * 创建套件后，验证回调URL创建有效事件（第一次保存回调URL之前）
     */
    private static final String CHECK_URL = "check_url";

    /**
     * 审批任务回调
     */
    private static final String BPMS_TASK_CHANGE = "bpms_task_change";

    /**
     * 审批实例回调
     */
    private static final String BPMS_INSTANCE_CHANGE = "bpms_instance_change";

    /**
     * 相应钉钉回调时的值
     */
    private static final String CALLBACK_RESPONSE_SUCCESS = "success";

    @RequestMapping(value = "/callback", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, String> callback(@RequestParam(value = "signature", required = false) String signature,
            @RequestParam(value = "timestamp", required = false) String timestamp,
            @RequestParam(value = "nonce", required = false) String nonce,
            @RequestBody(required = false) JSONObject json) {
        String params = " signature:" + signature + " timestamp:" + timestamp + " nonce:" + nonce + " json:" + json;
        mainLogger.info("收到请求:" + params);
        try {
            DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(Constant.TOKEN, Constant.ENCODING_AES_KEY,
                    Constant.CORP_ID);

            // 从post请求的body中获取回调信息的加密数据进行解密处理
            String encryptMsg = json.getString("encrypt");
            String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp, nonce, encryptMsg);
            JSONObject obj = JSON.parseObject(plainText);

            // 根据回调数据类型做不同的业务处理
            String eventType = obj.getString("EventType");
            if (StringUtils.equals(BPMS_TASK_CHANGE, eventType)) {
                bizLogger.info("收到审批任务进度更新(BPMS_TASK_CHANGE UPDATE): " + plainText);
                // todo: 实现审批的业务逻辑，如发消息
            } else if (StringUtils.equals(BPMS_INSTANCE_CHANGE, eventType)) {
                bizLogger.info("收到审批实例状态更新(BPMS_INSTANCE_CHANGE UPDATE): " + plainText);
                // todo: 实现审批的业务逻辑，如发消息
                JSONObject parseObject = JSON.parseObject(plainText);
                String processInstanceId = obj.getString("processInstanceId");
                // 审批开始
                if (StringUtils.equals(parseObject.getString("processCode"),
                        "PROC-A58FB763-8AB6-4A50-B3D1-7265EF6C4ABD")) {
                    // H5附件发起的审批
                    if (StringUtils.equals(parseObject.getString("type"), "finish")) {
                        // 审批正常结束（同意或拒绝）的type为finish
                        ProcessInstanceVO vo = new ProcessInstanceVO();
                        vo.setStatus(ProcessStatus.COMPLETED.code());
                        vo.setResult(parseObject.getString("result"));
                        vo.setProcessInstanceId(processInstanceId);
                        vo.setFinish_time(parseObject.getDate("finishTime"));
                        processInstanceService.update(vo);
                        bizLogger.info("BPMS_INSTANCE_CHANGE update finish!!!!");
                    } else if (StringUtils.equals(parseObject.getString("type"), "terminate")) {
                        // 审批终止的type为terminate
                        ProcessInstanceVO vo = new ProcessInstanceVO();
                        vo.setStatus(ProcessStatus.TERMINATED.code());
                        vo.setProcessInstanceId(processInstanceId);
                        vo.setFinish_time(parseObject.getDate("finishTime"));
                        processInstanceService.update(vo);
                        bizLogger.info("BPMS_INSTANCE_CHANGE terminate!!!!");
                    }

                }

                if (obj.containsKey("result") && obj.getString("result").equals("agree")) {
                    MessageUtil.sendMessageToOriginator(processInstanceId);
                }
            } else {
                // 其他类型事件处理
            }

            // 返回success的加密信息表示回调处理成功
            return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(),
                    Utils.getRandomStr(8));
        } catch (Exception e) {
            // 失败的情况，应用的开发者应该通过告警感知，并干预修复
            mainLogger.error("process callback failed！" + params, e);
            return null;
        }

    }

    public static void main(String[] args) throws Exception {
        // 先删除企业已有的回调
        DingTalkClient client = new DefaultDingTalkClient(URLConstant.DELETE_CALLBACK);
        OapiCallBackDeleteCallBackRequest request = new OapiCallBackDeleteCallBackRequest();
        request.setHttpMethod("GET");
        client.execute(request, AuthHelper.getAccessToken());

        // 重新为企业注册回调
        client = new DefaultDingTalkClient(URLConstant.REGISTER_CALLBACK);
        OapiCallBackRegisterCallBackRequest registerRequest = new OapiCallBackRegisterCallBackRequest();
        registerRequest.setUrl(Constant.CALLBACK_URL_HOST + "/callback");
        registerRequest.setAesKey(Constant.ENCODING_AES_KEY);
        registerRequest.setToken(Constant.TOKEN);
        registerRequest.setCallBackTag(Arrays.asList("bpms_instance_change", "bpms_task_change"));
        OapiCallBackRegisterCallBackResponse registerResponse = client.execute(registerRequest,
                AuthHelper.getAccessToken());
        if (registerResponse.isSuccess()) {
            System.out.println("回调注册成功了！！！");
        }
    }
}
